package com.cdream.basic.java8.io.niochat;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Set;

/**
 * @author cdream
 * @date 2022/8/16
 */
@Slf4j
public class ChatClient {
    private static final Integer PORT = 18080;
    private static final String HOST = "localhost";
    private static final String QUIT = "QUIT";
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    private static ByteBuffer wBuffer = ByteBuffer.allocate(1024);
    private static Selector selector;

    public static void main(String[] args) {
        SocketChannel client = null;
        try {
            client = SocketChannel.open();
            client.configureBlocking(false);

            selector = Selector.open();
            client.register(selector, SelectionKey.OP_CONNECT);

            client.connect(new InetSocketAddress(HOST, PORT));
            while (true) {
                int select = selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey selectionKey : selectionKeys) {
                    handlers(selectionKey);
                }
                selectionKeys.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handlers(SelectionKey selectionKey) throws IOException {
        // 连接就绪
        if (selectionKey.isConnectable()) {
            SocketChannel channel = (SocketChannel) selectionKey.channel();
            if (channel.isConnectionPending()) {
                channel.finishConnect();
                // 处理用户输入的信息
                Thread thread = new Thread(() -> {
                    handlerInput(selectionKey);
                });
                thread.setDaemon(true);
                thread.start();
            }
            channel.register(selector,SelectionKey.OP_READ);
        }
        if (selectionKey.isReadable()) {
            SocketChannel channel = (SocketChannel) selectionKey.channel();
            // channel.read(rBuffer);
            String msg = receiveMsg(channel);
            if (StrUtil.isEmpty(msg)){
                IoUtil.close(selector);
            }else {
                log.info(msg);
            }
        }

    }

    private static String receiveMsg(SocketChannel channel) throws IOException {
        rBuffer.clear();
        while(channel.read(rBuffer)>0);
        rBuffer.flip();
        return String.valueOf(StandardCharsets.UTF_8.decode(rBuffer));
    }


    @SneakyThrows
    public static void handlerInput(SelectionKey selectionKey) {
        while (true) {
            BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
            String consoleStr = console.readLine();

            wBuffer.clear();
            wBuffer.put(StandardCharsets.UTF_8.encode(consoleStr));
            wBuffer.flip();
            SocketChannel channel = (SocketChannel) selectionKey.channel();
            while (wBuffer.hasRemaining()) {
                channel.write(wBuffer);
            }

            if (QUIT.equals(consoleStr)) {
                IoUtil.close(selector);
            }
        }

    }

    @SneakyThrows
    public static String receiveMsg(BufferedReader br) {
        String serverStr = br.readLine();
        return serverStr;

    }

}
